# Конспект практических занятий по курсу ООП на C++ для студентов коломенского филиала московского Политеха. 

## Постановка задачи

  Целью практических занятий является знакомство студентов второго курса Коломенского Политеха Кафедры 
  Автоматизации Производства и Информационных Технологий с основами объектно-ориентированного программирования на 
  языке C++ и закрепления материала лекций по данному курсу. Обучение проводится на примере написания контейнера 
  типа вектор, созданного на основе массива. 

  Исходные коды, которые можно взять за образец для проведения занятий, доступны по следующим адресам:
  [GitVerse](https://gitverse.ru/polytech_kolomna/ivt21_oop_task_vector) и 
  [GitFlic](https://gitflic.ru/project/polytech_kolomna/ivt21_oop_task_vector). 
  

--------

## Занятие 1: написание первого класса, знакомство с инкапсуляцией.

### Цель
 - Изучить синтаксис написания класса: конструктор/деструктор, базовые методы, поля данных, модификаторы видимости.

### План
 - Составить перечень минимально необходимых данных и методов класса Vector.
 - Реализовать класс Vector на основе результатов обсуждения.
 - Самостоятельная работа: реализовать методы Insert и Erase.

### Работа на занятии
 - Обсудить со студентами минимально необходимый интерфейс класса Vector: конструктор/деструктор, присваивание, 
   доступ по индексу, размер. Также обсудить, какие данные класса должны быть открытыми, а какие закрытыми.
 - На основе обсуждения реализовать вместе со студентами класс Vector. Отдельно обратить внимание студентов на опасность 
   наличия умолчательной реализации конструктора копирования и оператора присваивания и необходимость их явной 
   реализации. Для упрощения работы с классом Vector реализовать вывод его содержимого на экран через перегрузку 
   функции operator<<.
 - Для закрепления пройденного материала предложить студентам самостоятельно реализовать методы вставки и удаления 
   элемента.

### Дополнение

  <details><summary>Ожидаемый вывод, после запуска программы с репозитория:</summary>
  
  ```console
    v1 = {7.5, 7.5, 7.5, 7.5, 7.5}
    v1 = {7.5, 7.5, 5, 7.5, 7.5, 7.5, 6}
    v1 = {7.5, 7.5, 7.5, 7.5, 6}
    v2 = {7.5, 7.5, 5, 7.5, 7.5, 7.5, 6}
    v3 = {7.5, 7.5, 5, 7.5, 7.5, 7.5, 6}
    v1 = {7.5, 7.5, 7.5, 7.5, 6}
    v2 = {7.5, 7.5, 5, 7.5, 7.5, 7.5, 6}
    v3 = {7.5, 7.5, 7.5, 7.5, 6}

    Process finished with exit code 0 (необязательная строка)
  ```
  
  </details>

--------

## Занятие 2: основы тестирования

### Цель
  - Изучить технику юнит-тестирования.

### План
  - Покрыть тестами конструктор и метод At.
  - Перейти к DSL для написания тестов.
  - Самостоятельная работа: заменить метод At на [] и написать тесты, определить тестовый макрос ASSERT_NEAR

### Работа на занятии
 - Рассказать студентам, как правильно писать тестовые функции и как их называть. Объяснить, почему с тестами будет 
   удобнее работать, если ввести специальный предметно-ориентированный язык для написания тестов.
 - Обсудить со студентами какие ситуации могут возникнуть при работе конструктора, и реализовать вместе с ними тесты, 
   воспроизводящие эти ситуации. В ходе обсуждения указать на проблемы, которые могут возникнуть в некоторых краевых 
   ситуациях, например, при задании отрицательного размера. Объяснить, что способов обработки таких ситуаций может быть 
   несколько. Особо заострить внимание на обработке таких случаев с помощью исключений, закинув таким образом удочку на 
   следующее занятие. Предложить использовать для сравнения в тестах строковое представление содержимого объекта 
   класса Vector. Для этого реализовать вместе со студентами метод ToString.
 - Для закрепления материала предложить студентам заменить метод At на соответствующий "операторный" метод, причём в 
   двух его версиях: константном и неконстантном. После чего обсудить, почему можно переиспользовать тесты At для тестов 
   константной версии [] и предложить самостоятельно написать тесты для неконстантной версии [].
 - Дополнительно попросить студентов переписать оператор вывода в поток (operator<<) для объектов класса Vector таким 
   образом, чтобы он использовал метод ToString.

### Дополнение

  <details><summary>Ожидаемый вывод, после запуска программы с репозитория:</summary>
  
  ```console
    Running TestVector_Construct_Normal
    OK
    Running TestVector_Construct_Empty
    OK
    Running TestVector_Construct_NegativeSize
    OK
    Running TestVector_Construct_BiggerThanBuffer
        FAILED
    Expected: {7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5}
    Actual: {}
    Running TestVector_AtConst_Normal
    OK
    Running TestVector_AtConst_NegativeIndex
    OK
    Running TestVector_AtConst_TooBigIndex
    OK
    Running TestVector_At_Normal
    OK
    Running TestVector_At_NegativeIndex
    OK
    Running TestVector_At_TooBigIndex
    OK

    Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) (необязательная строка)
  ```

  </details>

--------

## Занятие 3: исключения, знакомство с наследованием

### Цель
  - Изучить исключений.
  - Изучить наследование.

### План
  - Составить перечень исключительных ситуаций, которые могут возникнуть при работе с конструктором.
  - Составить из перечисленных исключительных ситуаций иерархию классов и внедрить их в код класса Vector.
  - Внедрить обработку исключений в тесты.
  - Самостоятельная работа: реализовать исключения, возникающие при работе с оператором [] и методами Erase и Insert.

### Работа на занятии
  - Обсудить со студентами исключительные ситуации, которые могут возникнуть при некорректном задании размера 
    в конструкторе класса Vector: задание отрицательного размера + задание размера, превышающего вместимость контейнера.
  - На основе обсуждения реализовать вместе со студентами базовый класс иерархии исключений VectorException и его 
    наследник VectorSizeException. Реализации всех обговоренных выше исключительных ситуаций должны наследоваться от
    класса VectorSizeException. Внедрить разработанные исключения в код класса Vector. 
  - Для знакомства студентов с обработкой исключительных ситуаций переписать тесты конструкторов Construct_NegativeSize 
    и Construct_BiggerThanBuffer таким образом, чтобы в них обрабатывались исключительные ситуации. После этого 
    предложить студентам расширить DSL тестов на случай, когда мы ожидаем возникновения исключительной ситуации в тесте.
  - Для закрепления пройденного материала предложить студентам самостоятельно расширить иерархию исключений на ситуации,
    которые могут возникнуть при работе с оператором [] и внедрить новые исключения в код класса Vector и тесты.

### Дополнение

  <details><summary>Ожидаемый вывод, после запуска программы с репозитория:</summary>

  ```console
    --------
    Running test Vector.Construct_Normal:
    OK
    --------
    Running test Vector.Construct_Empty:
    OK
    --------
    Running test Vector.Construct_NegativeSize:
    OK
   	    Vector size cannot be negative (size = -5)
    --------
    Running test Vector.Construct_BiggerThanCapacity:
    OK
	    Vector size (size = 12) is bigger than its capacity (capacity = 10)
    --------
    Running test Vector.AtConst_Normal:
    OK
    --------
    Running test Vector.AtConst_NegativeIndex:
    OK
	    Bad Vector index = -1 but Vector allowed indexes = [0, 4]
    --------
    Running test Vector.AtConst_TooBigIndex:
    OK
	    Bad Vector index = 12 but Vector allowed indexes = [0, 4]
    --------
    Running test Vector.At_Normal:
    OK
    --------
    Running test Vector.At_NegativeIndex:
    OK
	    Bad Vector index = -1 but Vector allowed indexes = [0, 4]
    --------
    Running test Vector.At_TooBigIndex:
    OK
	    Bad Vector index = 8 but Vector allowed indexes = [0, 4]

    Process finished with exit code 0 (необязательная строка)
  ```

  </details>

--------

## Занятие 4: шаблоны

### Цель
  - Изучить синтаксис создания шаблонных классов.
  - Изучить частичную специализацию шаблонных классов.

### План
  - Параметризовать (шаблонизировать) в классе Vector тип хранимых данных и размер буфера
  - Адаптировать тесты к новому виду класса Vector
  - Самостоятельная работа: написать специализацию класса Vector для величины буфера равной -1, при которой данные будут 
    храниться в динамическом массиве, и покрыть её тестами.

### Работа на занятии
  - Обсудить со студентами, зачем нужно класс Vector сделать шаблонным и как проще всего это сделать. Параметрами 
    шаблона предложить взять тип хранимых элементов и размер буфера контейнера, предназначенного для хранения элементов. 
    Объяснить, почему шаблонный класс, включая определения методов, должен быть полностью определён в заголовочном файле.
  - Вместе со студентами переписать тесты, добавив к имени семейства тип, для которого пишутся тесты.
  - Для закрепления пройденного материала предложить студентам самостоятельно реализовать частичную специализацию класса 
    Vector для размера буфера равного -1 таким образом, чтобы память под буфер в данной специализации выделялась 
    динамически. Перед началом выполнения работы обсудить со студентами код каких методов при этом изменится, а каких 
    останется прежним. 

### Дополнение

  <details><summary>Ожидаемый вывод, после запуска программы с репозитория:</summary>

  ```console
    --------
    Running test VectorStaticDouble.Construct_Normal:
    OK
    --------
    Running test VectorStaticDouble.Construct_Empty:
    OK
    --------
    Running test VectorStaticDouble.Construct_NegativeSize:
    OK
        Vector size cannot be negative (size = -5)
    --------
    Running test VectorStaticDouble.Construct_BiggerThanCapacity:
    OK
        Vector size (size = 12) is bigger than its capacity (capacity = 10)
    --------
    Running test VectorStaticDouble.AtConst_Normal:
    OK
    --------
    Running test VectorStaticDouble.AtConst_NegativeIndex:
    OK
        Bad Vector index = -1 but Vector allowed indexes = [0, 4]
    --------
    Running test VectorStaticDouble.AtConst_TooBigIndex:
    OK
        Bad Vector index = 12 but Vector allowed indexes = [0, 4]
    --------
    Running test VectorStaticDouble.At_Normal:
    OK
    --------
    Running test VectorStaticDouble.At_NegativeIndex:
    OK
        Bad Vector index = -1 but Vector allowed indexes = [0, 4]
    --------
    Running test VectorStaticDouble.At_TooBigIndex:
    OK
        Bad Vector index = 8 but Vector allowed indexes = [0, 4]
    --------
    Running test VectorDynamicDouble.Construct_Normal:
    OK
    --------
    Running test VectorDynamicDouble.Construct_Empty:
    OK
    --------
    Running test VectorDynamicDouble.Construct_NegativeSize:
    OK
        Vector size cannot be negative (size = -5)
    --------
    Running test VectorDynamicDouble.AtConst_Normal:
    OK
    --------
    Running test VectorDynamicDouble.AtConst_NegativeIndex:
    OK
        Bad Vector index = -1 but Vector allowed indexes = [0, 4]
    --------
    Running test VectorDynamicDouble.AtConst_TooBigIndex:
    OK
        Bad Vector index = 12 but Vector allowed indexes = [0, 4]
    --------
    Running test VectorDynamicDouble.At_Normal:
    OK
    --------
    Running test VectorDynamicDouble.At_NegativeIndex:
    OK
        Bad Vector index = -1 but Vector allowed indexes = [0, 4]
    --------
    Running test VectorDynamicDouble.At_TooBigIndex:
    OK
        Bad Vector index = 8 but Vector allowed indexes = [0, 4]
    
    Process finished with exit code 0 (необязательная строка)
  ```

  </details>

--------

## Занятие 5: полиморфизм

### Цель
  - познакомиться с реализацией полиморфизма на основе наследования

### План
  - Сделать класс VectorException полностью абстрактным и переопределить во всех классах иерархии исключений метод what. 
  - Реализовать два режима работы программы: тестовый и основной (рабочий).
  - Самостоятельная работа: на основе задачи по генерации различных геометрических фигур из прошлых семестров,
    создать иерархию геометрических фигур с базовым абстрактным классом Figure и виртуальными методами Area, Perimeter и
    Type.

### Работа на занятии

  - Вместе со студентами переделать класс VectorException в полностью абстрактный, сделав метод what чисто виртуальным.
    После переопределения этого метода во всех классах иерархии, проанализировать то, как теперь стал работать вывод 
    сообщения об ошибке.
  - Показать студентам, как можно задать несколько конфигураций сборки программы с помощью макросов и опции компиляции 
    и объяснить зачем это нужно, реализовав совместно с ними две конфигурации сборки программы: конфигурацию для запуска 
    тестов и конфигурацию для основного режима работы программы.
  - Для закрепления пройденного материала предложить студентам взять код задачи из предыдущих семестров (о генерации 
    набора случайных геометрических фигур: прямоугольника, прямоугольного треугольника и круга) и переделать код 
    из этой задачи таким образом, чтобы появилась иерархия наследования с полностью абстрактным классом Figure c двумя 
    чисто виртуальными методами: Area, Perimeter и Type. А также предложить реализовать в основном режиме работы 
    программы заполнение контейнера Vector сотней случайно сгенерированных фигур с последующим выводом их площади, 
    периметра и типа на экран.
